
#pragma once
#include "tick.h"

#define Pic_JPG		0
#define Pic_PNG		1
#define Pic_BMP		2
#define Pic_GIF		3
#define Pic_SLIP	4

#define SLIP_ROTATE	0x10
#define SLIP_SLIP	0x11
#define SLIP_GIF	0x12
#define SLIP_JIGSAW	0x13
#define Pic_SLIP_ROTATE		((SLIP_ROTATE << 4) | Pic_SLIP)
#define Pic_SLIP_SLIP		((SLIP_SLIP << 4) | Pic_SLIP)
#define Pic_SLIP_GIF		((SLIP_GIF << 4) | Pic_SLIP)
#define Pic_SLIP_JIGSAW		((SLIP_JIGSAW << 4) | Pic_SLIP)

typedef struct _stSlipHead {
	_stSlipHead() {}
	_stSlipHead(int type) { memcpy_s(mark, 4, "SLIP", 4); slipType = type; }
	char mark[4];
	int slipType;
} stSlipHead;
typedef struct {
	__int64 largeLength;
	__int64 smallLength;
} stSlipOther;
typedef struct {
	int picLength[9];
} stSlipJigsaw;

class CVARBinary
{
public:
	CVARBinary();
	CVARBinary(byte*d, intptr_t dLen);
	CVARBinary(LPCSTR s);
	virtual ~CVARBinary();

	__forceinline byte *getData() const { return data; }
	__forceinline intptr_t getLength() const { return dataLen; }
	__forceinline bool IsEmpty() const { return !data || dataLen <= 0; }

	void clear();
	void Detach();
	byte* Detach(intptr_t & dLen);
	void Attach(byte*d, intptr_t dLen);
	void Attach(CVARBinary &v);
	bool set(const byte*d, intptr_t dLen);
	bool set(const CVARBinary &v) { return set((const byte*)v.getData(), v.getLength()); };
	bool appendData(LPCVOID d, intptr_t dLen, bool appendZero);
	static bool isSWF(const byte *d, intptr_t l);
	__forceinline bool isSWF() { return CVARBinary::isSWF(data, dataLen); }
	static intptr_t getPicFormat(const byte *d, intptr_t l);
	__forceinline intptr_t getPicFormat() const { return CVARBinary::getPicFormat(data, dataLen); }
	static HBITMAP getBitmap(const byte *d, intptr_t l, bool keepAlpha = false);
	__forceinline HBITMAP getBitmap() const { return CVARBinary::getBitmap(data, dataLen); }
	static HGLOBAL getHGlobal(const byte *d, intptr_t l);
	__forceinline HGLOBAL getHGlobal() const { return CVARBinary::getHGlobal(data, dataLen); }
	static IStream * getIStream(const byte *d, intptr_t l);
	__forceinline IStream * getIStream() const { return CVARBinary::getIStream(data, dataLen); }

	__forceinline bool appendInt(int v) { return appendData(&v, sizeof(int), false); }
	bool appendWSTR(LPCWSTR v);
	bool appendSTR(LPCSTR v);
	bool appendBinary(const CVARBinary&data);
	__forceinline void ResetPos() { readPos = 0; }
	__forceinline void SkipPos(intptr_t skip, bool current){ if (current) readPos += skip; else readPos = skip; }
	
	bool readBool(bool &v);
	bool readInt(int &v);
#ifdef _WIN64
	__forceinline bool readInt(intptr_t &v) { int x; if (!readInt(x)) return false; v = x; return true; }
#endif
	bool readWSTR(LPCWSTR &v);
	bool readSTR(LPCSTR &v);
	bool readBinary(CVARBinary &v);
	bool readData(LPCVOID &v, size_t sz);
	const byte *find(const byte*v, intptr_t vLen) const;

	__forceinline size_t leftLength() const { return data && dataLen > readPos ? (dataLen - readPos) : 0; }
	bool enlargeSize(size_t sz);
	static size_t serialSize(LPCWSTR v);
	static size_t serialSize(LPCSTR v);

	bool writeBool(bool v);
	bool writeInt(int v);
	bool writeWSTR(LPCWSTR v);
	bool writeSTR(LPCSTR v);
	bool writeData(LPCVOID v, size_t sz);
#ifndef _CHKCODEDLL
	bool rdoutData(LPVOID v, size_t sz);
	bool rdoutWSTR(LPCWSTR &v);
	bool rdoutSTR(LPCSTR &v);
#endif
protected:
	static void HIMETRICtoDP(HDC hdc, LPSIZE lpSize);
		
	intptr_t readPos, dataLen;
	byte *data;
};
